package parser;

import flowchart.*;
import flowchart.Module;
import scanner.MyScanner;


import exceptions.*;
import util.*;

import java.io.IOException;
import java.util.*;

/**
 * 语法和语义Parser
 */
class OberonParser implements MyParser {


    /**
     * lookahead
     */
    private final LinkedList<Token> lookahead = new LinkedList<>();
    /**
     * scanner
     */
    private final MyScanner scanner;

    // 符号表
    public LinkedList<Var> vars = new LinkedList<>();
    public Map<String, Var.Type> typedef = new LinkedHashMap<>(); // 变量重命名的 map,


    /**
     * 构造函数，获取第一个lookahead
     *
     * @param scanner scanner
     * @throws java.io.IOException IOException
     * @throws LexicalException    LexicalException
     */
    public OberonParser(MyScanner scanner) throws java.io.IOException, LexicalException {
        this.scanner = scanner;
        this.lookahead.addLast(scanner.getNext());
        this.lookahead.addLast(scanner.getNext());

        typedef.put("INTEGER", new Var.Type(Var.Type.BasicType.INTEGER));
        typedef.put("BOOLEAN", new Var.Type(Var.Type.BasicType.BOOLEAN));
        typedef.put("ARRAY", new Var.Type(Var.Type.BasicType.ARRAY));
        typedef.put("RECORD", new Var.Type(Var.Type.BasicType.RECORD));
    }

    /**
     * @return lookahead 的行号
     */
    @Override
    public int getLine() {
        return this.lookahead.getFirst().row;
    }

    /**
     * @return lookahead 的列号
     */
    @Override
    public int getColumn() {
        return this.lookahead.getFirst().col;
    }

    /**
     * parse入口
     */
    @Override
    public void parse() throws java.io.IOException, LexicalException, SyntacticException, SemanticException {
        moduleNT();
    }

    private String posMessageInEx() {
        return String.format("位置：行 %s，列 %s，", getLine(), getColumn());
    }

    /**
     * 匹配一个 lookahead, 并获取下一个 lookahead
     *
     * @param tokenType 待匹配的 token 类型
     * @return 该匹配成功的 lookahead
     */
    private Token match(int tokenType) throws java.io.IOException, LexicalException, SyntacticException, SemanticException {
        if (this.lookahead.getFirst().type == tokenType) {
            Token ret = this.lookahead.pollFirst();
            this.lookahead.addLast(scanner.getNext());
            return ret;
        }
        throw new SyntacticException(String.format("期望匹配 %s 类型，但是 lookahead 是 %s" + posMessageInEx(), TokenType.names[tokenType], this.lookahead) + posMessageInEx());
    }

    /**
     * 判断 lookahead 的类型是否是指定类型
     *
     * @param types 指定类型
     * @return lookahead 的类型是否是指定类型
     */
    private boolean lookaheadIs(int... types) {
        for (int type : types) if (lookahead.getFirst().type == type) return true;
        return false;
    }

    /**
     * 判断 lookahead 的类型是否是指定类型
     *
     * @param types 指定类型
     * @return lookahead 的类型是否是指定类型
     */
    private boolean lookahead2Is(int... types) {
        for (int type : types) if (lookahead.getLast().type == type) return true;
        return false;
    }


    private void moduleNT() throws IOException, LexicalException, SyntacticException, SemanticException {
//        moduleNT ::= MODULE IDENTIFIER SEMICOLON declarations beginStatementSequenceSelect END IDENTIFIER PERIOD;
        match(TokenType.MODULE);
        String id1 = match(TokenType.IDENTIFIER).text;
        Module module = new Module(id1); // 创建流程图
        match(TokenType.SEMICOLON);
        declarations(module);
        beginStatementSequenceSelect(module.add("Main")); // 在模块中新建主函数
        match(TokenType.END);
        String id2 = match(TokenType.IDENTIFIER).text;
        match(TokenType.PERIOD);
        if (!id1.equals(id2)) throw new SemanticException("语义错误：模块名不一致" + posMessageInEx());
        module.show();
    }

    private void beginStatementSequenceSelect(Procedure procedure) throws IOException, LexicalException, SyntacticException, SemanticException {
//        beginStatementSequenceSelect ::= BEGIN StatementSequence | /*ε*/;
        if (lookaheadIs(TokenType.BEGIN)) {
            match(TokenType.BEGIN);
            StatementSequence sequence = new StatementSequence(); // 创建语句序列
            statementSequence(sequence); // 更新语句序列
            procedure.add(sequence); // 加入函数体
        } else {
            /*ε*/
        }
    }

    private void declarations(Module module) throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarations ::= declarationsConstSelect declarationsTypeSelect declarationsVarSelect declarationsProcedureClosure;
        LinkedList<Var> list1 = declarationsConstSelect(); // 因为与插入顺序有关，所以合并成列表再逐个插入
        vars.addAll(list1);
        declarationsTypeSelect(); // typdef added，因为与插入顺序无关，所以可以直接插入
        LinkedList<Var> list2 = declarationsVarSelect();
        vars.addAll(list2);
        LinkedList<Var> list3 = declarationsProcedureClosure(module);
        vars.addAll(list3);
    }

    private LinkedList<Var> declarationsConstSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsConstSelect ::= CONST declarationsConstSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.CONST)) {
            match(TokenType.CONST);
            return declarationsConstSelectClosure();
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private void declarationsTypeSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsTypeSelect ::= TYPE declarationsTypeSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.TYPE)) {
            match(TokenType.TYPE);
            declarationsTypeSelectClosure();
        } else {
            /*ε*/
        }
    }

    private LinkedList<Var> declarationsVarSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsVarSelect ::= VAR declarationsVarSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.VAR)) {
            match(TokenType.VAR);
            return declarationsVarSelectClosure();
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> declarationsConstSelectClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsConstSelectClosure ::= IDENTIFIER EQ expression SEMICOLON declarationsConstSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            String id1 = match(TokenType.IDENTIFIER).text;
            match(TokenType.EQ);
            Var expr1 = expression();
            match(TokenType.SEMICOLON);
            LinkedList<Var> list1 = declarationsConstSelectClosure();
            list1.addFirst(new Var(expr1.type, id1));
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private void declarationsTypeSelectClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsTypeSelectClosure ::= IDENTIFIER EQ typeNT SEMICOLON declarationsTypeSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            String id1 = match(TokenType.IDENTIFIER).text;
            match(TokenType.EQ);
            Var.Type type1 = typeNT();
            match(TokenType.SEMICOLON);
            declarationsTypeSelectClosure();
            typedef.put(id1, type1);
        } else {
            /*ε*/
        }
    }

    private LinkedList<Var> declarationsVarSelectClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsVarSelectClosure ::= identifierList COLON typeNT SEMICOLON declarationsVarSelectClosure | /*ε*/;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            LinkedList<String> list1 = identifierList();
            match(TokenType.COLON);
            Var.Type type1 = typeNT();
            match(TokenType.SEMICOLON);
            LinkedList<Var> list2 = declarationsVarSelectClosure();
            LinkedList<Var> retList = new LinkedList<>();
            for (String identifier : list1) {
                retList.addLast(new Var(type1, identifier));
            }
            retList.addAll(list2);
            return retList;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> declarationsProcedureClosure(Module module) throws IOException, LexicalException, SyntacticException, SemanticException {
//        declarationsProcedureClosure ::= procedureDeclaration SEMICOLON declarationsProcedureClosure | /*ε*/;
        if (lookaheadIs(TokenType.PROCEDURE)) {
            Var var1 = procedureDeclaration(module);
            match(TokenType.SEMICOLON);
            LinkedList<Var> list1 = declarationsProcedureClosure(module);
            list1.addFirst(var1);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private Var procedureDeclaration(Module module) throws IOException, LexicalException, SyntacticException, SemanticException {
//        procedureDeclaration ::= procedureHeading SEMICOLON procedureBody;
        Var procedureHeading = procedureHeading();
        String id1 = procedureHeading.identifier;
        if (module == null) throw new UnsupportedOperationException("禁止在函数内部声明函数");
        Procedure procedure = module.add(id1); // 在流程图中注册函数
        match(TokenType.SEMICOLON);
        // 将函数头压栈
        vars.addLast(procedureHeading);
        // 记录帧指针
        int fp = vars.size();
        // 将形参压入栈
        vars.addAll(procedureHeading.type.follow);
        // 分析函数体
        String id2 = procedureBody(procedure); // 传入流程图中该函数的指针
        // 弹出局部变量
        while (vars.size() > fp) vars.pollLast();
        if (vars.isEmpty() || !vars.getLast().equals(procedureHeading))
            throw new UnsupportedOperationException("弹出栈时出错，没有遇到函数名，请检查 cup 文件" + posMessageInEx());
        // 弹出函数头
        vars.pollLast();
        // 检查过程名
        if (!id1.equals(id2)) throw new SemanticException("语义分析：过程名不匹配" + posMessageInEx());
        return procedureHeading;
    }

    private String procedureBody(Procedure procedure) throws IOException, LexicalException, SyntacticException, SemanticException {
//        procedureBody ::=  declarations beginStatementSequenceSelect END IDENTIFIER;
        int fp = vars.size(); // 记录帧指针
        declarations(null);
        beginStatementSequenceSelect(procedure);
        while (vars.size() > fp) vars.pollLast(); // 弹出直至帧指针
        match(TokenType.END);
        String id1 = match(TokenType.IDENTIFIER).text;
        return id1;
    }

    private Var procedureHeading() throws IOException, LexicalException, SyntacticException, SemanticException {
//        procedureHeading ::= PROCEDURE IDENTIFIER procedureHeadingFormalParametersSelect;
        match(TokenType.PROCEDURE);
        String id1 = match(TokenType.IDENTIFIER).text;
        LinkedList<Var> list1 = procedureHeadingFormalParametersSelect();

        // 在符号表中注册函数
        Var.Type type = new Var.Type(Var.Type.BasicType.PROCEDURE);
        type.follow = list1;
        return new Var(type, id1);
    }

    private LinkedList<Var> procedureHeadingFormalParametersSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//         procedureHeadingFormalParametersSelect ::= formalParameters | /*ε*/;
        if (lookaheadIs(TokenType.L_ROUND_BRACKET)) {
            return formalParameters();
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> formalParameters() throws IOException, LexicalException, SyntacticException, SemanticException {
//        formalParameters ::= L_ROUND_BRACKET formalParametersSelect R_ROUND_BRACKET;
        match(TokenType.L_ROUND_BRACKET);
        LinkedList<Var> list1 = formalParametersSelect();
        match(TokenType.R_ROUND_BRACKET);
        return list1;
    }

    private LinkedList<Var> formalParametersSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        formalParametersSelect ::= fpSection formalParametersClosure | /*ε*/;
        if (lookaheadIs(TokenType.VAR, TokenType.IDENTIFIER)) {
            LinkedList<Var> list1 = fpSection();
            LinkedList<Var> list2 = formalParametersClosure();
            list1.addAll(list2);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> formalParametersClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        formalParametersClosure ::= SEMICOLON fpSection formalParametersClosure | /*ε*/;
        if (lookaheadIs(TokenType.SEMICOLON)) {
            match(TokenType.SEMICOLON);
            LinkedList<Var> list1 = fpSection();
            LinkedList<Var> list2 = formalParametersClosure();
            list1.addAll(list2);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> fpSection() throws IOException, LexicalException, SyntacticException, SemanticException {
//        fpSection ::= varSelect identifierList COLON typeNT;
        varSelect();
        LinkedList<String> list1 = identifierList();
        match(TokenType.COLON);
        Var.Type type1 = typeNT();
        LinkedList<Var> retList = new LinkedList<>();
        for (String identifier : list1) {
            retList.addLast(new Var(type1, identifier));
        }
        return retList;
    }

    private void varSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        varSelect ::= VAR | /*ε*/;
        if (lookaheadIs(TokenType.VAR)) {
            match(TokenType.VAR);
        } else {
            /*ε*/
        }
    }

    private Var.Type typeNT() throws IOException, LexicalException, SyntacticException, SemanticException {
//        typeNT ::= IDENTIFIER | arrayType | recordType;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            String id1 = match(TokenType.IDENTIFIER).text;
            if (!typedef.containsKey(id1))
                throw new SemanticException("语义错误：出现未定义的变量类型" + posMessageInEx());
            return typedef.get(id1);
        } else if (lookaheadIs(TokenType.ARRAY)) {
            return arrayType();
        } else if (lookaheadIs(TokenType.RECORD)) {
            return recordType();
        } else {
            throw new SyntacticException("typeNT" + posMessageInEx());
        }

    }

    private Var.Type recordType() throws IOException, LexicalException, SyntacticException, SemanticException {
//        recordType ::= RECORD fieldList recordTypeFieldListClosure END;
        match(TokenType.RECORD);
        LinkedList<Var> list1 = fieldList();
        LinkedList<Var> list2 = recordTypeFieldListClosure();
        match(TokenType.END);
        Var.Type retType = new Var.Type(Var.Type.BasicType.RECORD);
        retType.follow = list1;
        retType.follow.addAll(list2);
        return retType;
    }

    private LinkedList<Var> recordTypeFieldListClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        recordTypeFieldListClosure ::= SEMICOLON fieldList recordTypeFieldListClosure | /*ε*/;
        if (lookaheadIs(TokenType.SEMICOLON)) {
            match(TokenType.SEMICOLON);
            LinkedList<Var> list1 = fieldList();
            LinkedList<Var> list2 = recordTypeFieldListClosure();
            list1.addAll(list2);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> fieldList() throws IOException, LexicalException, SyntacticException, SemanticException {
//        fieldList ::= identifierList COLON typeNT | /*ε*/;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            LinkedList<String> list1 = identifierList();
            match(TokenType.COLON);
            Var.Type type1 = typeNT();
            LinkedList<Var> retList = new LinkedList<>();
            for (String identifier : list1) {
                retList.addLast(new Var(type1, identifier));
            }
            return retList;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private Var.Type arrayType() throws IOException, LexicalException, SyntacticException, SemanticException {
//        arrayType ::= ARRAY expression OF typeNT;
        match(TokenType.ARRAY);
        expression();
        match(TokenType.OF);
        Var.Type type1 = typeNT();
        Var.Type retType = new Var.Type(Var.Type.BasicType.ARRAY);
        retType.follow.addLast(new Var(type1, "[]"));
        return retType;
    }


    private LinkedList<String> identifierList() throws IOException, LexicalException, SyntacticException, SemanticException {
//        identifierList ::= IDENTIFIER identifierListClosure;
        String id1 = match(TokenType.IDENTIFIER).text;
        LinkedList<String> list1 = identifierListClosure();
        list1.addFirst(id1);
        return list1;
    }

    private LinkedList<String> identifierListClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        identifierListClosure ::= COMMA IDENTIFIER identifierListClosure | /*ε*/;
        if (lookaheadIs(TokenType.COMMA)) {
            match(TokenType.COMMA);
            String id1 = match(TokenType.IDENTIFIER).text;
            LinkedList<String> list1 = identifierListClosure();
            list1.addFirst(id1);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private void statementSequence(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        statementSequence ::= statement statementSequenceClosure;
        statement(sequence);
        statementSequenceClosure(sequence);

    }

    private void statementSequenceClosure(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        statementSequenceClosure ::= SEMICOLON statement statementSequenceClosure | /*ε*/;
        if (lookaheadIs(TokenType.SEMICOLON)) {
            match(TokenType.SEMICOLON);
            statement(sequence);
            statementSequenceClosure(sequence);
        } else {
            /*ε*/
        }
    }

    private void statement(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        statement ::= assignment | procedureCall | ifStatement | whileStatement | /*ε*/;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            if (lookahead2Is(TokenType.PERIOD, TokenType.L_SQRUARE_BRACKET, TokenType.ASSIGN)) {
                assignment(sequence);
            } else { // 不判断 first 集而直接调用会有风险，但是有道理。
                procedureCall(sequence);
            }
        } else if (lookaheadIs(TokenType.IF)) {
            ifStatement(sequence);
        } else if (lookaheadIs(TokenType.WHILE)) {
            whileStatement(sequence);
        } else {
            /*ε*/
        }
    }


    private void whileStatement(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        whileStatement ::= WHILE expression DO statementSequence END;
        match(TokenType.WHILE);
        Var expr1 = expression();
        if (expr1.type.basicType != Var.Type.BasicType.BOOLEAN)
            throw new SemanticException("语义错误：while 的判断语句不是 bool" + posMessageInEx());
        WhileStatement whileStatement1 = new WhileStatement("while " + expr1.identifier); // 构造 while 语句
        match(TokenType.DO);
        statementSequence(whileStatement1.getLoopBody()); // 初始化 while 的循环体
        match(TokenType.END);
        sequence.add(whileStatement1); // 放入 while 语句
    }

    private void ifStatement(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//    ifStatement ::= IF expression THEN statementSequence ifStatementElsifClosure ifStatementElseSelect END;
        match(TokenType.IF);
        Var expr1 = expression();
        if (expr1.type.basicType != Var.Type.BasicType.BOOLEAN)
            throw new SemanticException("语义错误：if 的判断语句不是 bool" + posMessageInEx());
        IfStatement ifStatement1 = new IfStatement("if " + expr1.identifier); // if 语句
        match(TokenType.THEN);
        statementSequence(ifStatement1.getTrueBody()); // 更新 true
        StatementSequence elseifFalse = ifStatementElsifClosure(ifStatement1.getFalseBody()); // 更新 false，并返回需要更新的 elseifFalse
        ifStatementElseSelect(elseifFalse);
        match(TokenType.END);
        sequence.add(ifStatement1);
    }

    // 返回需要回填的 false 块
    private StatementSequence ifStatementElsifClosure(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//    ifStatementElsifClosure ::= ELSIF expression THEN statementSequence ifStatementElsifClosure | /*ε*/;
        if (lookaheadIs(TokenType.ELSIF)) {
            match(TokenType.ELSIF);
            Var expr1 = expression();
            if (expr1.type.basicType != Var.Type.BasicType.BOOLEAN)
                throw new SemanticException("语义错误：elsif 的判断语句不是 bool" + posMessageInEx());
            IfStatement ifStatement1 = new IfStatement("if " + expr1.identifier); // if 语句
            sequence.add(ifStatement1); // 将 if 语句放入序列
            match(TokenType.THEN);
            statementSequence(ifStatement1.getTrueBody()); // 更新 true
            return ifStatementElsifClosure(ifStatement1.getFalseBody()); // 更新 false，并返回需要更新的 elseifFalse
        } else {
            return sequence; /*ε*/
        }
    }

    private void ifStatementElseSelect(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//    ifStatementElseSelect ::= ELSE statementSequence | /*ε*/;
        if (lookaheadIs(TokenType.ELSE)) {
            match(TokenType.ELSE);
            statementSequence(sequence);
        } else {
            /*ε*/
        }

    }

    private void procedureCall(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        procedureCall ::= IDENTIFIER procedureCallSelect;
        String id1 = match(TokenType.IDENTIFIER).text;
        LinkedList<Var> list1 = procedureCallSelect();
        // 在符号表中寻找 id1 对应的变量
        Var procedure = Utils.findLastOf(vars, id1);
        if (procedure == null || procedure.type.basicType != Var.Type.BasicType.PROCEDURE)
            throw new SemanticException("语义错误：在符号表中未找到该函数" + posMessageInEx());
        // 检查参数数量
        if (procedure.type.follow.size() != list1.size())
            throw new SemanticException("语义错误：函数调用参数数量错误" + posMessageInEx());
        // 检查参数类型
        ListIterator<Var> srcIt, tarIt;
        srcIt = procedure.type.follow.listIterator(); // 形参列表
        tarIt = list1.listIterator(); // 实参列表
        while (tarIt.hasNext()) {
            Var srcVar = srcIt.next(); // 形参
            Var tarVar = tarIt.next(); // 实参
            if (!tarVar.type.equals(srcVar.type))
                throw new SemanticException("语义错误：函数调用参数类型错误" + posMessageInEx());
        }
        // 构造 call 语句的参数列表
        StringBuilder ap = new StringBuilder(); // 实参列表
        for (Var var : list1) {
            ap.append(String.format("%s, ", var.identifier));
        }
        sequence.add(new PrimitiveStatement(String.format("%s(%s)", id1, ap)));
    }

    private LinkedList<Var> procedureCallSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        procedureCallSelect ::= actualParameters | /*ε*/;
        if (lookaheadIs(TokenType.L_ROUND_BRACKET)) {
            return actualParameters();
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> actualParameters() throws IOException, LexicalException, SyntacticException, SemanticException {
//        actualParameters ::= L_ROUND_BRACKET actualParametersSelect R_ROUND_BRACKET;
        match(TokenType.L_ROUND_BRACKET);
        LinkedList<Var> list1 = actualParametersSelect();
        match(TokenType.R_ROUND_BRACKET);
        return list1;
    }

    private LinkedList<Var> actualParametersSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        actualParametersSelect ::= expression actualParametersClosure | /*ε*/;
        if (lookaheadIs(TokenType.PLUS, TokenType.MINUS, TokenType.IDENTIFIER, TokenType.INTEGER_NUMBER, TokenType.L_ROUND_BRACKET, TokenType.NOT)) {
            Var expr1 = expression();
            LinkedList<Var> list1 = actualParametersClosure();
            list1.addFirst(expr1);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private LinkedList<Var> actualParametersClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        actualParametersClosure ::= COMMA expression actualParametersClosure | /*ε*/;
        if (lookaheadIs(TokenType.COMMA)) {
            match(TokenType.COMMA);
            Var expr1 = expression();
            LinkedList<Var> list1 = actualParametersClosure();
            list1.addFirst(expr1);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }

    private void assignment(StatementSequence sequence) throws IOException, LexicalException, SyntacticException, SemanticException {
//        assignment ::= IDENTIFIER selector ASSIGN expression;
        String id1 = match(TokenType.IDENTIFIER).text;
        LinkedList<Object> list1 = selector();
        match(TokenType.ASSIGN);
        Var expr1 = expression();
        Var now = Utils.findLastOf(vars, id1); // 在符号表中寻找 id1 对应的变量
        if (now == null)
            throw new SemanticException("语义错误：赋值语句时，在符号表中未找到该变量" + posMessageInEx() + vars);
        now = Utils.decodeSelector(now, list1, null); // 如果 list1 是空，那么自然会返回 now
        if (!now.type.equals(expr1.type))
            throw new SemanticException("语义错误：赋值语句两侧的类型不同" + posMessageInEx());
        sequence.add(new PrimitiveStatement(String.format("%s ::= %s", id1, expr1.identifier)));
    }


    private Var expression() throws IOException, LexicalException, SyntacticException, SemanticException {
//        expression ::= simpleExpression expressionSelect;
        Var expr1 = simpleExpression();
        Tuple2<Integer, Var> tmpTuple2 = expressionSelect();
        if (tmpTuple2 == null) return expr1;
        if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
            throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
        return Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second);
    }

    private Tuple2<Integer, Var> expressionSelect() throws IOException, LexicalException, SyntacticException, SemanticException {
//        expressionSelect ::=
//    EQ simpleExpression
//    | NEQ simpleExpression
//    | LT simpleExpression
//    | LE simpleExpression
//    | GT simpleExpression
//    | GE simpleExpression
//    | /*ε*/;
        if (lookaheadIs(TokenType.EQ)) {
            match(TokenType.EQ);
            return new Tuple2<>(TokenType.EQ, simpleExpression());
        } else if (lookaheadIs(TokenType.NEQ)) {
            match(TokenType.NEQ);
            return new Tuple2<>(TokenType.NEQ, simpleExpression());
        } else if (lookaheadIs(TokenType.LT)) {
            match(TokenType.LT);
            return new Tuple2<>(TokenType.LT, simpleExpression());
        } else if (lookaheadIs(TokenType.LE)) {
            match(TokenType.LE);
            return new Tuple2<>(TokenType.LE, simpleExpression());
        } else if (lookaheadIs(TokenType.GT)) {
            match(TokenType.GT);
            return new Tuple2<>(TokenType.GT, simpleExpression());
        } else if (lookaheadIs(TokenType.GE)) {
            match(TokenType.GE);
            return new Tuple2<>(TokenType.GE, simpleExpression());
        } else {
            return null; /*ε*/
        }
    }

    private Var simpleExpression() throws IOException, LexicalException, SyntacticException, SemanticException {
//        simpleExpression ::= term simpleExpressionClosure
//                    | PLUS term simpleExpressionClosure
//                    | MINUS term simpleExpressionClosure;
        if (lookaheadIs(TokenType.IDENTIFIER, TokenType.INTEGER_NUMBER, TokenType.L_ROUND_BRACKET, TokenType.NOT)) {
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (tmpTuple2 == null) return expr1;
            return Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second);
        } else if (lookaheadIs(TokenType.PLUS)) {
            match(TokenType.PLUS);
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (tmpTuple2 == null) return expr1;
            return Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second);
        } else if (lookaheadIs(TokenType.MINUS)) {
            match(TokenType.MINUS);
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (tmpTuple2 == null) return expr1;
            return Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second);
        } else {
            throw new SyntacticException("simpleExpression" + posMessageInEx());
        }
    }

    private Tuple2<Integer, Var> simpleExpressionClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        simpleExpressionClosure ::= PLUS term simpleExpressionClosure
//                            | MINUS term simpleExpressionClosure
//                            | OR term simpleExpressionClosure
//                            | /*ε*/;
        if (lookaheadIs(TokenType.PLUS)) {
            match(TokenType.PLUS);
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.PLUS, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.PLUS, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));


        } else if (lookaheadIs(TokenType.MINUS)) {
            match(TokenType.MINUS);
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.MINUS, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.MINUS, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));


        } else if (lookaheadIs(TokenType.OR)) {
            match(TokenType.OR);
            Var expr1 = term();
            Tuple2<Integer, Var> tmpTuple2 = simpleExpressionClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.OR, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.OR, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));


        } else {
            return null; /*ε*/
        }
    }

    private Var term() throws IOException, LexicalException, SyntacticException, SemanticException {
//        term ::= factor termClosure;
        Var expr1 = factor();
        Tuple2<Integer, Var> tmpTuple2 = termClosure();
        if (tmpTuple2 == null) return expr1;
        return Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second);
    }

    private Tuple2<Integer, Var> termClosure() throws IOException, LexicalException, SyntacticException, SemanticException {
//        termClosure ::=
//        TIMES factor termClosure
//        | DIVIDE factor termClosure
//        | MOD factor termClosure
//        | AND factor termClosure
//        | /*ε*/;
        if (lookaheadIs(TokenType.TIMES)) {
            match(TokenType.TIMES);
            Var expr1 = factor();
            Tuple2<Integer, Var> tmpTuple2 = termClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.TIMES, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.TIMES, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));
        } else if (lookaheadIs(TokenType.DIVIDE)) {
            match(TokenType.DIVIDE);
            Var expr1 = factor();
            Tuple2<Integer, Var> tmpTuple2 = termClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.DIVIDE, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.DIVIDE, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));
        } else if (lookaheadIs(TokenType.MOD)) {
            match(TokenType.MOD);
            Var expr1 = factor();
            Tuple2<Integer, Var> tmpTuple2 = termClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.MOD, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.MOD, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));
        } else if (lookaheadIs(TokenType.AND)) {
            match(TokenType.AND);
            Var expr1 = factor();
            Tuple2<Integer, Var> tmpTuple2 = termClosure();
            if (expr1 == null) throw new SemanticException("语义错误：缺少运算数" + posMessageInEx());
            if (tmpTuple2 == null) return new Tuple2<>(TokenType.AND, expr1);
            if (!Utils.isLegalTypeAsExpression(expr1, tmpTuple2.first, tmpTuple2.second))
                throw new SemanticException("语义错误：表达式类型错误" + posMessageInEx());
            return new Tuple2<>(TokenType.AND, Utils.makeVarAsExpression(expr1, tmpTuple2.first, tmpTuple2.second));
        } else {
            return null; /*ε*/
        }
    }

    private Var factor() throws IOException, LexicalException, SyntacticException, SemanticException {
//        factor ::= IDENTIFIER selector
//        | INTEGER_NUMBER
//        | L_ROUND_BRACKET expression R_ROUND_BRACKET
//        | NOT factor;
        if (lookaheadIs(TokenType.IDENTIFIER)) {
            String id1 = match(TokenType.IDENTIFIER).text;
            LinkedList<Object> list1 = selector();

            StringBuilder retIdentifier = new StringBuilder(id1);
            Var now = Utils.findLastOf(vars, id1); // 在符号表中寻找 id1 对应的变量
            if (now == null) throw new SemanticException("语义错误：在符号表中未找到该变量" + posMessageInEx());
            now = Utils.decodeSelector(now, list1, retIdentifier);
            return new Var(now.type, retIdentifier.toString());

        } else if (lookaheadIs(TokenType.INTEGER_NUMBER)) {
            String number = match(TokenType.INTEGER_NUMBER).text;
            return new Var(new Var.Type(Var.Type.BasicType.INTEGER), number);
        } else if (lookaheadIs(TokenType.L_ROUND_BRACKET)) {
            match(TokenType.L_ROUND_BRACKET);
            Var expr1 = expression();
            match(TokenType.R_ROUND_BRACKET);
            return expr1;
        } else if (lookaheadIs(TokenType.NOT)) {
            match(TokenType.NOT);
            Var expr2 = factor();
            if (!Utils.isLegalTypeAsExpression(null, TokenType.NOT, expr2))
                throw new SemanticException("语义错误：表达式类型错误，not 后不是 bool" + posMessageInEx());
            return Utils.makeVarAsExpression(null, TokenType.NOT, expr2);
        } else {
            throw new SyntacticException("factor" + posMessageInEx());
        }
    }

    private LinkedList<Object> selector() throws IOException, LexicalException, SyntacticException, SemanticException {
//        selector ::= PERIOD IDENTIFIER selector
//        | L_SQRUARE_BRACKET expression R_SQRUARE_BRACKET selector
//        | /*ε*/;
        if (lookaheadIs(TokenType.PERIOD)) {
            match(TokenType.PERIOD);
            String id1 = match(TokenType.IDENTIFIER).text;
            LinkedList<Object> list1 = selector();
            list1.addFirst(id1);
            return list1;
        } else if (lookaheadIs(TokenType.L_SQRUARE_BRACKET)) {
            match(TokenType.L_SQRUARE_BRACKET);
            Var expr1 = expression();
            match(TokenType.R_SQRUARE_BRACKET);
            LinkedList<Object> list1 = selector();
            list1.addFirst(expr1);
            return list1;
        } else {
            return new LinkedList<>(); /*ε*/
        }
    }
}
